package com.dz.risk.config.dbconf;


import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.dz.risk.config.MsgConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;

/**
 * @author baohan
 * @className DataSourceConfig
 * @description druid config
 * @date 2021/4/27 10:02
 */
@Slf4j
@Configuration
public class DataSourceConfig {

    @Resource
    MsgConfig msgConfig;

    //初始化大小
    private static final int initialSize = 1;
    //最小连接数
    private static final int minIdle = 1;
    //最大连接数
    private static final int maxActive = 800;
    //获取连接等待超时时间
    private static final int maxWait = 50000;
    //间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒
    private static final int timeBetweenEvictionRunsMillis = 100000;
    //一个连接在池中最小生存的时间，单位是毫秒
    private static final int minEvictableIdleTimeMillis = 300000;
    private static final String validationQuery = "select 'x'";
    // 配置监控统计拦截的filters，监控统计用的stat、日志用的log4j、 防御sql注入的wall
    String filters = "stat,wall,logback";
    int maxPoolPreparedStatementPerConnectionSize = 30;

    @Bean
    public DataSource druidDataSource() {
        log.info("==================================== InitDatabaseConfig -> dataSource -> 开始创建数据库 ====================================");
        // 数据库连接对象
        Connection connection = null;
        Statement statement = null;
        String url = msgConfig.getMysqlUrl();
        String driverClassName = msgConfig.getMysqlDriverName();
        String username = msgConfig.getMysqlUsername();
        String password = msgConfig.getMysqlPassword();
        try {
            // 如果尝试去连接不存在的数据库会报错，所以这里连接的时候不带数据库名称
            String connectionUrl = url.replace(("/" + (url.substring(0, url.indexOf("?"))).substring(((url.substring(0, url.indexOf("?"))).lastIndexOf("/")) + 1)), "");
            // 从连接地址中截取出数据库名称
            String databaseName = (url.substring(0, url.indexOf("?"))).substring(((url.substring(0, url.indexOf("?"))).lastIndexOf("/")) + 1);
            // 设置驱动
            Class.forName(driverClassName);
            // 连接数据库
            connection = DriverManager.getConnection(connectionUrl, username, password);
            statement = connection.createStatement();
            // 创建数据库
            statement.executeUpdate("create database if not exists `" + databaseName + "` default character set utf8mb4 COLLATE utf8mb4_general_ci");
        } catch (Exception e) {
            e.printStackTrace();
            log.info("==================================== InitDatabaseConfig -> dataSource -> 创建数据库出错：" + e.getMessage() + " ====================================");
        } finally {
            try {
                // 关闭连接
                statement.close();
                connection.close();
            } catch (SQLException e) {
                log.info("==================================== InitDatabaseConfig -> dataSource -> 关闭数据库出错：" + e.getMessage() + " ====================================");
            }
            log.info("==================================== InitDatabaseConfig -> dataSource -> 创建数据库结束 ====================================");
        }

        // 创建数据源
        DruidDataSource druidDataSource = new DruidDataSource();
        // 设置数据源
        druidDataSource.setDriverClassName(driverClassName);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setInitialSize(initialSize);
        druidDataSource.setMinIdle(minIdle);
        druidDataSource.setMaxActive(maxActive);
        druidDataSource.setMaxWait(maxWait);
        druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        druidDataSource.setValidationQuery(validationQuery);
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTestOnBorrow(false);
        druidDataSource.setTestOnReturn(false);
        druidDataSource.setPoolPreparedStatements(true);
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        try {
            druidDataSource.setFilters(filters);
            druidDataSource.init();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        // 返回数据源
        return druidDataSource;
    }

    /**
     * 注册Servlet信息， 配置数据库监控视图
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    public ServletRegistrationBean<Servlet> druidServlet() {
        ServletRegistrationBean<Servlet> servletRegistrationBean = new ServletRegistrationBean<Servlet>(new StatViewServlet(), "/druid/*");
        Map<String, String> initParameters = new HashMap<String, String>();
        //属性见：com.alibaba.druid.support.http.ResourceServlet
        initParameters.put("loginUsername", msgConfig.getLoginUsername());
        initParameters.put("loginPassword", msgConfig.getLoginPassword());
//        registrationBean.addInitParameter("allow", "127.0.0.1");// IP白名单 (没有配置或者为空，则允许所有访问)
//        registrationBean.addInitParameter("deny", "");// IP黑名单 (存在共同时，deny优先于allow)

        initParameters.put("allow", "");//默认允许所有
        initParameters.put("deny", "");
        servletRegistrationBean.setInitParameters(initParameters);
        return servletRegistrationBean;

    }

    /**
     * 注册Filter信息, 监控拦截器
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    public FilterRegistrationBean<Filter> filterRegistrationBean() {
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<Filter>();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}
